package com.uparlange.project.flextris
{
	import com.uparlange.project.flextris.vo.UserScoreVO;
	
	import flash.net.SharedObject;

	/**
	 * Score management
	 * 
	 * @author Ugo Parlange
	 */ 
	[Bindable]
	public class Score
	{
		/**
		 * Configuration
		 */ 
		public static const MAX_BEST_SCORES_TO_SAVE : int = 10;
		
		private static const LINES_LEVEL_UP : int = 10;
		private static const MAX_DELAY_INTERVAL : Number = 1000;
		private static const DELAY_INTERVAL : Number = 50;
		private static const MIN_DELAY_INTERVAL : Number = 50;
		
		/**
		 * Score value
		 */ 
		public var score : int = 0;
		
		/**
		 * Line count
		 */ 
		public var lines : int = 0;
		
		/**
		 * Level value
		 */ 
		public var level : int = 0; 
		
		/**
		 * Timer interval 
		 * @see flash.utils.Timer
		 */ 
		public var speed : int = MAX_DELAY_INTERVAL;
		
		/**
		 * Line count in a level
		 */ 
		private var levelLines : int = 0;
		
		/**
		 * List of user scores
		 */ 
		[ArrayElementType("com.uparlange.project.flextris.vo.UserScoreVO")]	
		private var scores : Array = new Array();
		
		/**
		 * Constructor
		 */ 
		public function Score() {
			super();
			init();
		}
		
		/**
		 * Add lines
		 * 
		 * @param aCount int, the number of lines to add
		 */ 
		public function addLines(aCount : int) : void {
			// update lines
			lines += aCount;
			// update levelLines
			levelLines += aCount;
			// check level update
			if(levelLines >= LINES_LEVEL_UP) {
				// play sound
				JukeBox.getInstance().playLevelUp();
				// update level
				levelUp();
				// init levelLines
				levelLines -= LINES_LEVEL_UP;
			}
			// update score
			score += getScore(aCount);
		}
		
		/**
		 * Level up
		 */
		public function levelUp() : void {
			// update level
			level++;
			// update speed
			if(speed > MIN_DELAY_INTERVAL) {
				speed = MAX_DELAY_INTERVAL - (level * DELAY_INTERVAL);
			}
		}
		
		/**
		 * Initialize the score
		 */ 
		public function raz() : void {
			levelLines = 0;
			speed = MAX_DELAY_INTERVAL;
			score = 0;
			lines = 0;
			level = 0;
		}
		
		/**
		 * Called to save current score
		 */ 
		public function saveCurrent() : void {
			// create user score
			var userScoreVO : UserScoreVO = new UserScoreVO();
			userScoreVO.level = level;
			userScoreVO.score = score;
			userScoreVO.lines = lines;
			// add score
			scores.push(userScoreVO);
			// save all
			saveScoresToDesktop();
			// reload
			scores = getSavedDesktopScores();
		}
		
		/**
		 * Called to get score list in String
		 * 
		 * @return String, the score list in String
		 */ 
		public function getScoreList() : String {
			var str_array : Array = new Array();
			for each(var userScoreVO : UserScoreVO in scores) {
				str_array.push(userScoreVO.toString());
			}
			return str_array.join("\n");
		}
		
		/**
		 * Called to get the best saved scores
		 * @see NB_SCORES_TO_SAVE
		 * 
		 * @return Array, the list of scores
		 */ 
		private function getSavedDesktopScores() : Array {
			var so : SharedObject = SharedObject.getLocal(Flextris.FLEXTRIS_SHARED_OBJECT);
			var ds : Array = new Array();
			if(so.data["scores"] != null) {
				ds = (so.data["scores"] as Array).sortOn("score", Array.NUMERIC|Array.DESCENDING);
			}
			while(ds.length > MAX_BEST_SCORES_TO_SAVE) {
				ds.pop();
			}
			return ds
		}
		
		/**
		 * Called to save all scores to desktop
		 */ 
		private function saveScoresToDesktop() : void {
			var so : SharedObject = SharedObject.getLocal(Flextris.FLEXTRIS_SHARED_OBJECT);
			so.clear();
			so.data["scores"] = scores;
			so.flush();
		}
		
		/**
		 * Initialize Score
		 */ 
		private function init() : void {
			scores = getSavedDesktopScores();
		}
		
		/**
		 * Get score value for a number of lines and a level
		 * 
		 * @param aLineCount int, the number of lines
		 * 
		 * @return int, the score value
		 */ 
		private function getScore(aLineCount : int) : int {
			if(aLineCount == 0) {
				return 0;
			}
			var s : int = 0;
			switch(aLineCount) {
				case 1 : s = 40; break;
				case 2 : s = 100; break;
				case 3 : s = 300; break;
				case 4 : s = 1200; break;
			}
			return s * (level + 1);
		}
	}
}